﻿using Communication.Model.netPacket;
using Communication.Model.packetType;
using Communication.Model.acceleration;
using Communication.Model.displacement;
using Communication.Model.helper;
using Communication.Model.slowSignal;
using Communication.Model.speedData;
using Communication.Model.speedRealTVol;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Communication.Model.configuration;

namespace Communication.TcpIpService.tcpAsynService
{
    public delegate void ReceivePacketHandler(NetPacket packet);
    public class TcpAsynService
    {
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="netStream"></param>
        public TcpAsynService(NetworkStream netStream)
        {
            this._netStream = netStream;
        }


        /// <summary>
        /// 临时缓存区的大小为1024
        /// </summary>
        private const Int32 BUFFER_SIZE = 65536;

        /// <summary>
        /// 缓存区实际数据长度
        /// </summary>
        private int _netDataOffset = 0;

        /// <summary>
        /// 接收网络数据的缓存区
        /// </summary>
        private byte[] _netDataBuffer = new byte[BUFFER_SIZE * 1600];//

        /// <summary>
        /// 临时缓存区
        /// </summary>
        private byte[] _tempBuffer = new byte[BUFFER_SIZE];

        /// <summary>
        /// 网络流
        /// </summary>
        protected NetworkStream _netStream = null;

        /// <summary>
        /// 在接收数据包之后触发的事件
        /// </summary>
        public event ReceivePacketHandler OnReceivedPacket;

        /// <summary>
        /// 发包前事件
        /// </summary>
        //public event ReceivePacketHandler OnBeforeSendPacket;

        /// <summary>
        /// 缓冲区是否满足一个完整包
        /// </summary>
        /// <returns></returns>
        protected Boolean IsFullNetPacket()
        {
            //如果缓存区实际数据的长度大于包头加包体的长度，则返回为true
            if (_netDataOffset >= NetPacketHead.HEAD_SIZE + BitConverter.ToInt32(_netDataBuffer, 8))
            {
                return true;
            }
            return false;
            //return _netDataOffset >= NetPacketHead.HEAD_SIZE + BitConverter.ToInt32(_netDataBuffer, 8);
        }

        /// <summary>
        /// 缓冲区是否满足一个完整包头
        /// </summary>
        /// <returns></returns>
        protected Boolean IsFullNetPacketHead()
        {
            return _netDataOffset >= NetPacketHead.HEAD_SIZE;
        }

        /// <summary>
        /// 一个完整的网络封包的大小
        /// </summary>
        protected Int32 FullNetPacketSize
        {
            get
            {
                if (!IsFullNetPacketHead())
                    throw new Exception("由于没有缓冲区数据不足一个包头大小因此不能获得完整网络封包大小");
                return NetPacketHead.HEAD_SIZE + BitConverter.ToInt32(_netDataBuffer, 8);
            }

        }

        /// <summary>
        /// 从缓冲区提取一个包头,但并不从缓冲区删除该包头
        /// </summary>
        /// <returns></returns>
        protected NetPacketHead PeekNetPacket()
        {
            NetPacketHead packetHead = new NetPacketHead();
            packetHead.Version = BitConverter.ToInt32(_netDataBuffer, 0);//版本
            packetHead.PacketType = (PacketType)BitConverter.ToInt32(_netDataBuffer, 4);//封包类型
            packetHead.BodyLen = BitConverter.ToInt32(_netDataBuffer, 8);
            return packetHead;
        }

        /// <summary>
        /// 从缓冲区提取一个网络包
        /// </summary>
        /// <returns></returns>
        protected NetPacket PickNetPacket()
        {

            #region
            NetPacketHead packetHead = PeekNetPacket();
            #endregion

            #region
            NetPacket packet = new NetPacket();
            packet.NetPacketHead = packetHead;
            Byte[] buffer = new Byte[packetHead.BodyLen];
            Array.Copy(_netDataBuffer, NetPacketHead.HEAD_SIZE, buffer, 0, packetHead.BodyLen);
            switch (packetHead.PacketType)
            {
                case PacketType.STRING:
                    packet.DataPacket = new SerializeHelper().DeSerializeString<string>(buffer);
                    //packet.DataPacket = new SerializeHelper().DeSerialize<DisplacementData>(buffer);
                    break;
                case PacketType.ACQParametersConfig:
                    packet.DataPacket = new SerializeHelper().DeSerialize<ACQParametersConfig>(buffer);
                    break;
                //case PacketType.ChannelConfig:
                //    packet.Data = Serializehelper<StructHelper>().DeSerialize<ChannelConfig>(buffer);
                //    break;
                case PacketType.DisplacementPacket:
                    packet.DataPacket = new SerializeHelper().DeSerialize<DisplacementData>(buffer);
                    break;
                case PacketType.AccelerationPacket:
                    packet.DataPacket = new SerializeHelper().DeSerialize<AccData>(buffer);
                    break;
                case PacketType.SpeedPacket:
                    packet.DataPacket = new SerializeHelper().DeSerialize<SpeedData>(buffer);
                    break;
                case PacketType.SpeedVoltagePacket:
                    packet.DataPacket = new SerializeHelper().DeSerialize<SpeedRealTVol>(buffer);
                    break;
                case PacketType.SlowSignalPacket:
                    packet.DataPacket = new SerializeHelper().DeSerialize<SlowSignal>(buffer);
                    break;
                default:
                    break;
            }
            #endregion

            #region
            Array.Copy(_netDataBuffer, NetPacketHead.HEAD_SIZE + packetHead.BodyLen, _netDataBuffer, 0, _netDataOffset - (NetPacketHead.HEAD_SIZE + packetHead.BodyLen));
            _netDataOffset -= (NetPacketHead.HEAD_SIZE + packetHead.BodyLen);//缓冲区实际数据长度减去一个完整封包长度
            #endregion

            return packet;
        }

        /// <summary>
        /// 接收包体
        /// </summary>
        public void ReceivePacket()
        {
            try
            {
                if (IsFullNetPacket())
                {
                    NetPacket packet = PickNetPacket();
                    GC.Collect();

                    if (OnReceivedPacket != null)
                    {
                        OnReceivedPacket(packet);
                    }

                }

                _netStream.BeginRead(_tempBuffer, 0, BUFFER_SIZE, new AsyncCallback(AsyncCallbackReadFromNetStream), _netStream);
            }
            catch (Exception ex)
            {
                if (ex.Message != "正常关闭连接")
                {

                }
                else
                {
                    throw new Exception("非正常连接关闭");
                }
                //workerThreadExceptionHandlerDelegate.BeginInvoke(ex, null, null);
            }
        }

        private void AsyncCallbackReadFromNetStream(IAsyncResult result)
        {

            int readLen = 0;
            try
            {
                NetworkStream netStream = (NetworkStream)result.AsyncState;
                readLen = netStream.EndRead(result);

                if (readLen + _netDataOffset > _netDataBuffer.Length)
                {
                    if (IsFullNetPacketHead())
                    {
                        Array.Resize<Byte>(ref _netDataBuffer, FullNetPacketSize);
                    }
                    else
                    {
                        Array.Resize<Byte>(ref _netDataBuffer, _netDataBuffer.Length + BUFFER_SIZE * 2);
                    }
                }
                Array.Copy(_tempBuffer, 0, _netDataBuffer, _netDataOffset, readLen);

                #region
                //NetPacketHead packetHead = new NetPacketHead();
                //packetHead.Version = BitConverter.ToInt32(_netDataBuffer, 0);//版本
                //packetHead.PType = (PacketType)BitConverter.ToInt32(_netDataBuffer, 4);//封包类型
                //packetHead.Len = BitConverter.ToInt32(_netDataBuffer, 8);
                #endregion



                _netDataOffset += readLen;

                ReceivePacket();


            }
            catch (Exception ex)
            {
                //workerThreadExceptionHandlerDelegate.BeginInvoke(ex, null, null);
            }
        }


        /// <param name="packet"></param>
        public void SendPacket(NetPacket packet)
        {
            if (packet == null || packet.DataPacket == null || packet.NetPacketHead == null)
                return;

            //if (OnBeforeSendPacket != null)
            //    OnBeforeSendPacket(packet);

            MemoryStream mStream = new MemoryStream();

            byte[] buffer = null;
            #region
            if (packet.NetPacketHead.BodyLen == 0)
            {
                switch (packet.NetPacketHead.PacketType)
                {
                    case PacketType.STRING:
                        string a = packet.DataPacket as string;
                        buffer = new SerializeHelper().SerializeString<string>(a);
                        packet.NetPacketHead.BodyLen = buffer.Length;
                        break;
                    case PacketType.ACQParametersConfig:
                        ACQParametersConfig acq = (ACQParametersConfig)packet.DataPacket;
                        buffer = new SerializeHelper().Serialize(acq);
                        packet.NetPacketHead.BodyLen = buffer.Length;
                        break;
                    //case PType.ChannelConfig:
                    //    ChannelConfig chc = (ChannelConfig)packet.Data;
                    //    buffer = Serializehelper<StructHelper>().Serialize(chc);
                    //    packet.PacketHead.Len = buffer.Length;
                    //    break;
                    case PacketType.DisplacementPacket:
                        NetPacket dataPacket = (NetPacket)packet.DataPacket;
                        buffer = new SerializeHelper().Serialize(dataPacket);
                        packet.NetPacketHead.BodyLen = buffer.Length;
                        break;
                    default:
                        break;
                }
            }

            #endregion

            #region
            //byte[] bt1 = BitConverter.GetBytes(packet.NetPacketHead.Version);
            //byte[] bt2 = BitConverter.GetBytes((Int32)packet.NetPacketHead.PacketType);
            //byte[] bt3 = BitConverter.GetBytes(packet.NetPacketHead.BodyLen);
            mStream.Write(BitConverter.GetBytes(packet.NetPacketHead.Version), 0, Marshal.SizeOf(packet.NetPacketHead.Version));
            mStream.Write(BitConverter.GetBytes((Int32)packet.NetPacketHead.PacketType), 0, sizeof(Int32));
            mStream.Write(BitConverter.GetBytes(packet.NetPacketHead.BodyLen), 0, Marshal.SizeOf(packet.NetPacketHead.BodyLen));
            #endregion

            #region
            //  byte[] buffer = null;
            //switch (packet.PacketHead.PType)
            //{
            //    case PacketType.STRING:
            //        buffer = Encoding.Default.GetBytes(Convert.ToString(packet.Data));
            //        break;
            //    case PacketType.BINARY:
            //        buffer = (byte[])packet.Data;
            //        break;
            //    case PacketType.COMPLEX:
            //        MemoryStream m = new MemoryStream();
            //        SerializeHelper<StructHelper>()(m, packet.Data);
            //        m.Position = 0;
            //        buffer = new byte[m.Length];
            //        m.Read(buffer, 0, (Int32)m.Length);
            //        break;
            //}
            if (buffer != null)
                mStream.Write(buffer, 0, buffer.Length);

            #endregion

            #region
            mStream.Seek(0, SeekOrigin.Begin);
            byte[] temp = mStream.GetBuffer();
            _netStream.BeginWrite(mStream.GetBuffer(), 0, (Int32)mStream.Length, new AsyncCallback(AsyncCallbackWriteToNetStream), new WriteNetStreamASyncCallbackParam { netStream = _netStream, packetHead = packet.NetPacketHead });
            #endregion
        }

        private void AsyncCallbackWriteToNetStream(IAsyncResult result)
        {
            try
            {
                //WriteNetStreamASyncCallbackParam p = (WriteNetStreamASyncCallbackParam)result.AsyncState;
                _netStream.EndWrite(result);
                //if (OnAfterSendPacket != null)//事件处理,如果注册了该事件,则执行回调函数
                //    OnAfterSendPacket(p.packetHead);
            }
            catch (Exception ex)
            {
                Console.WriteLine("写入网络流异步回调函数发生错误：" + ex.Message);
                //string a = e.Message.ToString();
            }
        }


        sealed class WriteNetStreamASyncCallbackParam
        {
            /// <summary>
            /// 网络流
            /// </summary>
            internal NetworkStream netStream;
            /// <summary>
            /// 包头
            /// </summary>
            internal NetPacketHead packetHead;
        }

        public void SendText(string content)
        {
            NetPacket packet = new NetPacket();
            NetPacketHead packetHead = new NetPacketHead();
            packet.NetPacketHead = packetHead;
            packet.DataPacket = content;
            packetHead.Version = 1;
            packetHead.PacketType = PacketType.STRING;
            SendPacket(packet);
        }

    }
}
